﻿using System;
using System.IO;
using System.Reflection;

namespace ExplorerPlus.Utilities
{
    public static class PluginManager
    {
        /// <summary>
        /// Detects whether an assembly is implementing a specific interface or not.
        /// </summary>
        /// <param name="interfaceName">The String containing the name of the interface to get. For generic interfaces, this is the mangled name.</param>
        /// <param name="assemblyFile">The name or path of the file that contains the manifest of the assembly.</param>
        /// <returns>true if one of the assembly classes implements the specified interface; otherwise, false.</returns>
        public static bool IsInterfaceImplemented(string interfaceName, string assemblyFile)
        {
            // ensure interface name is not null
            if (interfaceName != string.Empty && interfaceName != null && interfaceName.Length > 0)
            {
                // check if assembly file exists
                if (File.Exists(assemblyFile))
                {
                    //Create a new assembly from the plugin file 
                    Assembly pluginAssembly = Assembly.LoadFrom(assemblyFile);
                    //Next we'll loop through all the Types found in the assembly
                    foreach (Type pluginType in pluginAssembly.GetTypes())
                    {
                        if (pluginType.IsPublic) //Only look at public types
                        {
                            if (!pluginType.IsAbstract)  //Only look at non-abstract types
                            {
                                //Gets a type object of the interface we need the plugins to match
                                Type typeInterface = pluginType.GetInterface(interfaceName, true);

                                //Make sure the interface we want to use actually exists
                                if (typeInterface != null)
                                {
                                    return true;
                                }
                            }
                        }
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// Creates an instance of a class implementing a specific interface in a given assembly.
        /// </summary>
        /// <param name="interfaceName">The String containing the name of the interface to get. For generic interfaces, this is the mangled name.</param>
        /// <param name="assemblyFile">The name or path of the file that contains the manifest of the assembly.</param>
        /// <returns>Reference to the created instance if found; otherwise, null.</returns>
        public static object CreateInstance(string interfaceName, string assemblyFile)
        {
            // ensure interface name is not null
            if (interfaceName != string.Empty && interfaceName != null && interfaceName.Length > 0)
            {
                // check if assembly file exists
                if (File.Exists(assemblyFile))
                {
                    //Create a new assembly from the plugin file 
                    Assembly pluginAssembly = Assembly.LoadFrom(assemblyFile);
                    //Next we'll loop through all the Types found in the assembly
                    foreach (Type pluginType in pluginAssembly.GetTypes())
                    {
                        if (pluginType.IsPublic) //Only look at public types
                        {
                            if (!pluginType.IsAbstract)  //Only look at non-abstract types
                            {
                                //Gets a type object of the interface we need the plugins to match
                                Type typeInterface = pluginType.GetInterface(interfaceName, true);

                                //Make sure the interface we want to use actually exists
                                if (typeInterface != null)
                                {
                                    return Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
                                }
                            }
                        }
                    }
                }
            }

            return null;
        }
    }
}
